#include "inet_address.h"
#include <cstring>



InetAddress::InetAddress(const char* ip, uint16_t port, bool ipv6)
: ipv6_(ipv6) {
    if(ipv6) {
        memset(&addr6_, 0, sizeof(addr6_));
        addr6_.sin6_family = AF_INET6;
        addr6_.sin6_port = htons(port);
        if(ip == nullptr) {
            addr6_.sin6_addr = IN6ADDR_ANY;
        } else {
            assert(inet_pton(AF_INET6, ip, &addr6_.sin6_addr) > 0);
        }
    } else {
        memset(&addr_, 0, sizeof(addr_));
        addr_.sin_family = AF_INET;
        addr_.sin_port = htons(port);
        if(ip == nullptr) {
#ifdef _WIN32
            addr_.sin_addr.S_un.S_addr = IN4ADDR_ANY;
#elif __linux__
            addr_.sin_addr.s_addr = IN4ADDR_ANY;
#endif
        } else {
            assert(inet_pton(AF_INET, ip, &addr_.sin_addr) > 0);
        }
    }
}


InetAddress::InetAddress(in_addr_type addr)
: ipv6_(false)
, addr_(addr) {
}

InetAddress::InetAddress(in6_addr_type addr6)
: ipv6_(true)
, addr6_(addr6) {
}


// af_inet
uint16_t InetAddress::family() const {
    return addr_.sin_family;
}

uint16_t InetAddress::port() const {
    return ntohs(ipv6_ ? addr6_.sin6_port : addr_.sin_port);
}

bool InetAddress::isIpv6() const {
    return ipv6_;
}

std::string InetAddress::ip() const {
    char buf[65];
    memset(buf, 0, sizeof(buf));
    if(ipv6_) {
        inet_ntop(AF_INET6, (void*)&addr6_.sin6_addr, buf, sizeof(buf));
    } else {
        inet_ntop(AF_INET, (void*)&addr_.sin_addr, buf, sizeof(buf));
    }
    return std::string(buf);
}

std::string InetAddress::ipPort() const {
    return ip() + ":" + std::to_string(port());
}

sockaddr_type* InetAddress::addr() const {
    return (sockaddr_type*)&addr_;
}

